package com.ftwj.demo.permission.service.impl;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ftwj.demo.config.redis.RedisUtil;
import com.ftwj.demo.permission.dao.UserDao;
import com.ftwj.demo.permission.entity.UserBean;
import com.ftwj.demo.permission.service.UserService;
import com.ftwj.demo.permission.vo.LoginEntity;
import com.ftwj.demo.permission.vo.UserBeanVo;
import com.ftwj.demo.global.shiro.CustomShiroRealm;
import com.ftwj.demo.global.shiro.ShiroPrincipal;
import com.ftwj.demo.global.shiro.ShiroUtil;
import com.ftwj.demo.utils.StringHelper;
import com.ftwj.demo.utils.captcha.base.Captcha;
import com.ftwj.demo.utils.chinese.ChineseCharacterUtil;
import com.ftwj.demo.utils.exception.ValidateFailedException;
import com.ftwj.demo.utils.logs.LoggerUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.ObjectUtil;

/**
*
* <p>Title: UserServiceImpl</p>  
* <p>Description: 用户管理业务实现类</p>
* <p>Copyright: Copyright (c) 2020 </p>  
* <p>Company: 兰州飞天网景信息产业有限公司</p>    
* @author WangSLi
* @date 2020年4月4日 下午5:54:02
* @version V1.0
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, UserBean> implements UserService {
	
	@Autowired
	private UserDao dao;
	@Autowired
	private RedisUtil redis;
	@Autowired
	private CustomShiroRealm realm;
	
	/**
	 *	 用户登录业务逻辑
	 */
	@Override
	public String login(String phone,String password,Boolean remember) {
		Subject subject = SecurityUtils.getSubject();
		AuthenticationToken token=new UsernamePasswordToken(phone, password,remember);
		subject.login(token);
		Integer userId=ShiroUtil.getUserId();
        UserBean data=new UserBean();
        data.setUserId(userId);
        data.setLastLoginTime(LocalDateTime.now()); 
        dao.updateById(data);
        Serializable session = Optional.ofNullable(subject.getSession().getId()).orElse("");
        String sessionToken=session.toString();
		LoggerUtil.info("用户【{}】已成功登录，用户【TOKEN】:{}！",ShiroUtil.getShowName(),sessionToken);
		return sessionToken;
	}
	
	/**
	 * 	用户登录业务逻辑
	 */
	@Override
	public String login(LoginEntity login) {
        Object code = redis.get(login.getKey());
        if (code == null || !code.toString().equals(login.getCaptcha().trim().toLowerCase())) {
          // throw new  ValidateFailedException("数字验证码错误！");
        }
        login.setLoginname(StringHelper.isNotEmpty(login.getPhone())?login.getPhone():login.getUsername());
        AuthenticationToken token=new UsernamePasswordToken(login.getLoginname(), login.getPassword(),login.getRememberme());
		Subject subject = SecurityUtils.getSubject();
		subject.login(token);
		Integer userId=ShiroUtil.getUserId();
        UserBean data=new UserBean();
        data.setUserId(userId);
        data.setLastLoginTime(LocalDateTime.now()); 
        dao.updateById(data);
        Serializable session = Optional.ofNullable(subject.getSession().getId()).orElse("");
        String sessionToken=session.toString();
		LoggerUtil.info("用户【{}】已成功登录，用户【TOKEN】:{}！",ShiroUtil.getShowName(),sessionToken);
		return sessionToken;
	}

	/**
	 *	 用户退出业务逻辑（自定义账号密码）
	 */
	@Override
	public void logout() {
		Subject subject = SecurityUtils.getSubject();
		String userName = ShiroUtil.getShowName();
		subject.logout();
		if(null!=userName) {
			LoggerUtil.info("用户【{}】已退出！",userName);
		}
	}

	/**
	 * 	用户注册业务逻辑
	 */
	@Override
	public boolean register(UserBean user) {
		String salt=ShiroUtil.getSalt();
		String password=ShiroUtil.getMD5Password(salt, user.getPassword());
		user.setSalt(salt);
		user.setPassword(password);
		int create=ShiroUtil.getUserId()!=null?ShiroUtil.getUserId():0;
		user.setCreateUser(create);
		user.setCreateTime(LocalDateTime.now());
		user.setState(1);
		if(dao.insert(user)>0) {
			return true;
		} 
		return false;
	}
	
	/**
	 * 	获取用户信息
	 */
	@Override
	public UserBean getInfoById(Integer id){
		QueryWrapper<UserBean> queryWrapper=new QueryWrapper<UserBean>().eq("user_id", id).select(UserBean.class,info
				->!info.getColumn().equals("password")
				&&!info.getColumn().equals("salt")
				&&!info.getColumn().equals("state"));
		UserBean user=dao.selectOne(queryWrapper);
		//如果没有修改郭密码说明首次登录，需要修改密码
		if(ObjectUtil.isNull(user.getModiTime()) && ObjectUtil.isNull(user.getModiUser())){
			user=new UserBean();
		}
		return user;
	}

	/**
	 * 	条件查询
	 */
	@Override
	public List<Map<String, Object>> listMaps(UserBean bean) {
		QueryWrapper<UserBean> queryWrapper=new QueryWrapper<UserBean>(bean).select(UserBean.class,info
				->!info.getColumn().equals("password")
				&&!info.getColumn().equals("salt"));
		List<Map<String, Object>> data = dao.selectMaps(queryWrapper);
		return data;
	}
	
	/**
	 * 	分页条件查询
	 */
	@Override
	public IPage<Map<String, Object>> pageMaps(IPage<UserBean> page,UserBean bean) {
		QueryWrapper<UserBean> queryWrapper=new QueryWrapper<UserBean>(bean)
				.select(UserBean.class,info
				->!info.getColumn().equals("password")
				&&!info.getColumn().equals("salt"));
		IPage<Map<String, Object>> data = dao.selectMapsPage(page, queryWrapper);
		return data;
	}

	/**
	 * 	将验证码存入Redis
	 */
	@Override
	public Map<String, Object> captcah(Captcha captcha) {
		String key = UUID.randomUUID().toString().replace("-", "");
		String value = captcha.text().toLowerCase();
		redis.set(key, value, 300);
		Map<String,Object> map=new HashMap<>();
		map.put("key", key);
		map.put("image", captcha.toBase64());
		return map;
	}

	/**
	 * 	根据ID修改数据状态
	 */
	@Override
	public boolean updateStateById(Integer id,Integer state) {
		return dao.updateStateById(id,state);
	}

	/**
	 * 	添加用户，该方法仅管理员可用（用户名密码自生成）
	 */
	@Override
	public boolean insert(String phone, String showName) {
		QueryWrapper<UserBean> query=new QueryWrapper<>();
		query.eq("phone", phone);
		if(dao.selectCount(query)>0) {
			throw new ValidateException("该电话号码已存在！");
		}
		UserBean user=new UserBean();
		user.setPhone(phone);
		user.setShowName(showName);
		String pass=generatePassword(showName,phone);
		user.setLoginName(pass);
		user.setPassword(pass);
		String salt=ShiroUtil.getSalt();
		String password=ShiroUtil.getMD5Password(salt, user.getPassword());
		user.setSalt(salt);
		user.setPassword(password);
		int create=ShiroUtil.getUserId()!=null?ShiroUtil.getUserId():0;
		user.setCreateUser(create);
		user.setCreateTime(LocalDateTime.now());
		user.setState(1);
		if(dao.insert(user)>0) {
			return true;
		} 
		return false;
	}
	
	/**
	 * 
	 * <p>Title: generatePassword</p>  
	 * <p>Description: </p>  
	 * @param name 用户名
	 * @param phone 手机号码
	 * @return 
	 * @author WangSLi
	 * @date 2020年5月13日  
	 * @version 1.0
	 */
	private String generatePassword(String name,String phone) {
		String pinyin = ChineseCharacterUtil.getLowerCase(name, true);
		 String tail = StringHelper.substring(phone, 4, false);
		 return pinyin+"@"+tail;
	}

	/**
	 * 	用户密码修改
	 */
	@Override
	public boolean updatePassword(String userName, String oldPasssword, String newPasssword) {
		UserBean user = new UserBean();
		if(StringHelper.isNotEmpty(userName)) {
			Wrapper<UserBean> queryUserWrapper=new QueryWrapper<UserBean>().eq("state", 1).eq("phone", userName).or().eq("login_name", userName);
			user = getOne(queryUserWrapper);
		}else {
			Integer userId=ShiroUtil.getUserId();
			user = getById(userId);
		}
		if(user==null) {
			throw new ValidateFailedException("账户不存在！");
		}
		String MD5Password = ShiroUtil.getMD5Password(user.getSalt(), oldPasssword);
		if(!user.getPassword().equals(MD5Password)) {
			throw new ValidateFailedException("原密码错误！");
		}
		String newSalt = ShiroUtil.getSalt();
		String newMdD5Passsword = ShiroUtil.getMD5Password(newSalt, newPasssword);
		user.setSalt(newSalt);
		user.setPassword(newMdD5Passsword);
		user.setModiTime(LocalDateTime.now());
		user.setModiUser(user.getUserId());
		return updateById(user);
	}

	/**
	 * ·管理员重置用户密码·
	 */
	@Override
	public boolean reset(Integer id) {
		UserBean user = getById(id);
		String salt = ShiroUtil.getSalt();
		String MD5Password=ShiroUtil.getMD5Password(salt, user.getLoginName());
		user.setPassword(MD5Password);
		user.setSalt(salt);
		user.setModiTime(null);
		user.setModiUser(null);
		return updateById(user);
	}
	
	/**
	 * 	获取当前的认证对象
	 */
	@Override
	public ShiroPrincipal getShiroPrincipal(){
		realm.doGetAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
		return ShiroUtil.getPrincipal();
	}

	/**
	 *	 修改用户信息
	 */
	@Override
	public boolean updateVoById(UserBeanVo bean) {
		UserBean user=new UserBean();
		BeanUtil.copyProperties(bean, user);
		return updateById(user);
	}
	
}
